import glob
import math
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np
import random
import sklearn.metrics as metrics
from tensorflow.keras import optimizers
from tensorflow.keras.callbacks import ModelCheckpoint, CSVLogger, LearningRateScheduler
from tensorflow.keras.models import Model
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import add, concatenate, Conv2D, Dense, Dropout, Flatten, Input
from tensorflow.keras.layers import Activation, AveragePooling2D, BatchNormalization, MaxPooling2D
from tensorflow.keras.regularizers import l2
from tensorflow.keras.utils import to_categorical
%matplotlib inline
# Set up 'ggplot' style
plt.style.use('ggplot') # if want to use the default style, set 'classic'
plt.rcParams['ytick.right'] = True
plt.rcParams['ytick.labelright']= True
plt.rcParams['ytick.left'] = False
plt.rcParams['ytick.labelleft'] = False
plt.rcParams['font.family'] = 'Arial'
# where am i?
%pwd
flowers = glob.glob('./data/flr_*.jpg')
fungus = glob.glob('./data/fgs_*.jpg')
rocks = glob.glob('./data/rck_*.jpg')
pixel_flowers = glob.glob('./data/pxl_flower_*.jpeg')
pixel_umbrella = glob.glob('./data/pxl_umbrella_*.jpeg')
print("There are %s, %s flower, %s fungus, %s rock and %s umbrella pictures" %(len(flowers), len(pixel_flowers), len(fungus), len(rocks), len(pixel_umbrella)))
# Randomly show 10 examples of the images
from IPython.display import Image
dataset = flowers #flowers #fungus #rocks
for i in range(0, 5):
index = random.randint(0, len(dataset)-1)
print("Showing:", dataset[index])
img = mpimg.imread(dataset[index])
imgplot = plt.imshow(img)
plt.show()
#Image(dataset[index])
# Load the data
trDatOrg = np.load('flrnonflr-train-imgs96-0.8.npz')['arr_0']
trLblOrg = np.load('flrnonflr-train-labels96-0.8.npz')['arr_0']
tsDatOrg = np.load('flrnonflr-test-imgs96-0.8.npz')['arr_0']
tsLblOrg = np.load('flrnonflr-test-labels96-0.8.npz')['arr_0']
print("For the training and test datasets:")
print("The shapes are %s, %s, %s, %s" \
%(trDatOrg.shape, trLblOrg.shape, tsDatOrg.shape, tsLblOrg.shape))
# Randomly show 10 examples of the images
data = tsDatOrg
label = tsLblOrg
for i in range(20):
index = random.randint(0, len(data)-1)
print("Showing %s index image, It is %s" %(index, label[index]))
imgplot = plt.imshow(data[index])
plt.show()
# Convert the data into 'float32'
# Rescale the values from 0~255 to 0~1
trDat = trDatOrg.astype('float32')/255
tsDat = tsDatOrg.astype('float32')/255
# Retrieve the row size of each image
# Retrieve the column size of each image
imgrows = trDat.shape[1]
imgclms = trDat.shape[2]
channel = 3
# # reshape the data to be [samples][width][height][channel]
# # This is required by Keras framework
# trDat = trDat.reshape(trDat.shape[0], imgrows, imgclms, channel)
# tsDat = tsDat.reshape(tsDat.shape[0], imgrows, imgclms, channel)
# Perform one hot encoding on the labels
# Retrieve the number of classes in this problem
trLbl = to_categorical(trLblOrg)
tsLbl = to_categorical(tsLblOrg)
num_classes = tsLbl.shape[1]
# fix random seed for reproducibility
seed = 29
np.random.seed(seed)
modelname = 'FlowerPower'
def createBaselineModel():
inputs = Input(shape=(imgrows, imgclms, channel))
x = Conv2D(30, (4, 4), activation='relu')(inputs)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Conv2D(50, (4, 4), activation='relu')(x)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Dropout(0.3)(x)
x = Flatten()(x)
x = Dense(32, activation='relu')(x)
x = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=[inputs],outputs=x)
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
return model
optmz = optimizers.Adam(lr=0.001)
def resLyr(inputs,
numFilters=16,
kernelSz=3,
strides=1,
activation='relu',
batchNorm=True,
convFirst=True,
lyrName=None):
convLyr = Conv2D(numFilters, kernel_size=kernelSz, strides=strides,
padding='same', kernel_initializer='he_normal',
kernel_regularizer=l2(1e-4),
name=lyrName+'_conv' if lyrName else None)
x = inputs
if convFirst:
x = convLyr(x)
if batchNorm:
x = BatchNormalization(name=lyrName+'_bn' if lyrName else None)(x)
if activation is not None:
x = Activation(activation,name=lyrName+'_'+activation if lyrName else None)(x)
else:
if batchNorm:
x = BatchNormalization(name=lyrName+'_bn' if lyrName else None)(x)
if activation is not None:
x = Activation(activation, name=lyrName+'_'+activation if lyrName else None)(x)
x = convLyr(x)
return x
def resBlkV1(inputs,
numFilters=16,
numBlocks=3,
downsampleOnFirst=True,
names=None):
x = inputs
for run in range(0,numBlocks):
strides = 1
blkStr = str(run+1)
if downsampleOnFirst and run == 0:
strides = 2
y = resLyr(inputs=x, numFilters=numFilters, strides=strides,
lyrName=names+'_Blk'+blkStr+'_Res1' if names else None)
y = resLyr(inputs=y, numFilters=numFilters, activation=None,
lyrName=names+'_Blk'+blkStr+'_Res2' if names else None)
if downsampleOnFirst and run == 0:
x = resLyr(inputs=x, numFilters=numFilters, kernelSz=1,
strides=strides, activation=None, batchNorm=False,
lyrName=names+'_Blk'+blkStr+'_lin' if names else None)
x = add([x,y], name=names+'_Blk'+blkStr+'_add' if names else None)
x = Activation('relu', name=names+'_Blk'+blkStr+'_relu' if names else None)(x)
return x
def createResNetV1(inputShape=(imgrows, imgclms, channel),
numClasses=2):
inputs = Input(shape=inputShape)
v = resLyr(inputs, lyrName='Inpt')
v = resBlkV1(inputs=v, numFilters=16, numBlocks=3,
downsampleOnFirst=False, names='Stg1')
v = resBlkV1(inputs=v, numFilters=32, numBlocks=3,
downsampleOnFirst=True, names='Stg2')
v = resBlkV1(inputs=v, numFilters=64, numBlocks=3,
downsampleOnFirst=True, names='Stg3')
v = AveragePooling2D(pool_size=8, name='AvgPool')(v)
v = Flatten()(v)
outputs = Dense(numClasses, activation='softmax',
kernel_initializer='he_normal')(v)
model = Model(inputs=inputs,outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer=optmz,
metrics=['accuracy'])
return model
# Setup the models
model = createBaselineModel() # This is meant for training
modelGo = createBaselineModel() # This is used for final testing
model.summary()
# Create checkpoint for the training
# This checkpoint performs model saving when
# an epoch gives highest testing accuracy
# filepath = modelname + ".hdf5"
# checkpoint = ModelCheckpoint(filepath,
# monitor='val_acc',
# verbose=0,
# save_best_only=True,
# mode='max')
# # Log the epoch detail into csv
# csv_logger = CSVLogger(modelname +'.csv')
# callbacks_list = [checkpoint,csv_logger]
def lrSchedule(epoch):
lr = 1e-3
if epoch > 70:
lr *= 0.5e-3
elif epoch > 50:
lr *= 1e-3
elif epoch > 40:
lr *= 1e-2
elif epoch > 30:
lr *= 1e-1
print('Learning rate: ', lr)
return lr
LRScheduler = LearningRateScheduler(lrSchedule)
# Create checkpoint for the training
# This checkpoint performs model saving when
# an epoch gives highest testing accuracy
filepath = modelname + ".hdf5"
checkpoint = ModelCheckpoint(filepath,
monitor='val_acc',
verbose=0,
save_best_only=True,
mode='max')
# Log the epoch detail into csv
csv_logger = CSVLogger(modelname +'.csv')
#callbacks_list = [checkpoint, csv_logger, LRScheduler]
callbacks_list = [checkpoint, csv_logger]
# Fit the model
# This is where the training starts
model.fit(trDat,
trLbl,
validation_data=(tsDat, tsLbl),
epochs=120,
batch_size=32,
callbacks=callbacks_list)
# datagen = ImageDataGenerator(width_shift_range=0.1,
# height_shift_range=0.1,
# rotation_range=30,
# horizontal_flip=True,
# vertical_flip=False)
# model.fit_generator(datagen.flow(trDat, trLbl, batch_size=64),
# validation_data=(tsDat, tsLbl),
# epochs=120,
# verbose=1,
# steps_per_epoch=len(trDat)/64,
# callbacks=callbacks_list)
## Now the training is complete, we get
# another object to load the weights
# compile it, so that we can do
# final evaluation on it
modelGo.load_weights(filepath)
modelGo.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# Make classification on the test dataset
predicts = modelGo.predict(tsDat)
# Prepare the classification output
# for the classification report
predout = np.argmax(predicts,axis=1)
testout = np.argmax(tsLbl,axis=1)
labelname = ['flower', 'non-flower']
# the labels for the classfication report
testScores = metrics.accuracy_score(testout,predout)
confusion = metrics.confusion_matrix(testout,predout)
print("Best accuracy (on testing dataset): %.2f%%" % (testScores*100))
print(metrics.classification_report(testout,predout,target_names=labelname,digits=4))
print(confusion)
import pandas as pd
records = pd.read_csv(modelname +'.csv')
plt.figure()
plt.subplot(211)
plt.plot(records['val_loss'])
plt.plot(records['loss'])
plt.yticks([0, 0.20, 0.30, 0.4, 0.5])
plt.title('Loss value',fontsize=12)
ax = plt.gca()
ax.set_xticklabels([])
plt.subplot(212)
plt.plot(records['val_acc'])
plt.plot(records['acc'])
plt.yticks([0.7, 0.8, 0.9, 1.0])
plt.title('Accuracy',fontsize=12)
plt.show()
wrong_ans_index = []
for i in range(len(predout)):
if predout[i] != testout[i]:
wrong_ans_index.append(i)
wrong_ans_index = list(set(wrong_ans_index))
# Randomly show X examples of that was wrong
dataset = tsDatOrg #flowers #fungus #rocks
for index in wrong_ans_index:
#index = wrong_ans_index[random.randint(0, len(wrong_ans_index)-1)]
print("Showing %s index image" %(index))
print("Predicted as %s but is actually %s" %(predout[index], testout[index]))
imgplot = plt.imshow(data[index])
plt.show()